import type { ComponentExposed } from 'vue-component-type-helpers'
import type { LocationQuery } from 'vue-router'
import type { DataField, DataFormField } from '../DataField'

import type { PageReq, PageRes } from '@/apis/common/commonApi'
import type { DataQueryFormProp, DataTableProps } from '@/components/DataPage/types'
import { useUrlSearchParams } from '@vueuse/core'
import { omit } from 'lodash-es'
import { defineComponent, h, onMounted, reactive, ref, useTemplateRef } from 'vue'
import { useRoute, useRouter } from 'vue-router'
import DateTableFieldFilterButton from '@/components/DataPage/DateTableFieldFilterButton.vue'
import DataQueryForm from './DataQueryForm.vue'
import DataTable from './DataTable.vue'

export function useTable<Q extends PageReq | undefined, T>(
  { autoQuery = true, queryPage, tableFields = [], queryFields = [], defaultQuery, data }:
  {
    autoQuery?: boolean
    queryPage?: (params: Q) => Promise<PageRes<T>>
    tableFields: DataField[]
    queryFields?: DataFormField[]
    defaultQuery?: Partial<Q>
    data?: T[]
  },
) {
  const queryFormFields = reactive<DataFormField[]>(queryFields)
  let queryFormRef = useTemplateRef<ComponentExposed<typeof DataQueryForm>>('queryFormRef')
  const queryFormData = ref<Q>()

  const dataTableFields = reactive<DataField[]>(tableFields)
  let tableRef = useTemplateRef<ComponentExposed<typeof DataTable>>('tableRef')
  const tableData = ref<PageRes<T> | T[]>()

  if (queryPage) {
    queryFormData.value = { current: 1, size: 10, orderBy: 'id', orderAsc: false, ...defaultQuery } as Q
    tableData.value = { current: 1, size: 10, total: (data ?? []).length, records: data ?? [] }
  }
  else {
    queryFormData.value = {} as Q
    tableData.value = data ?? []
  }

  const router = useRouter()
  const route = useRoute()

  async function doQuery() {
    if (queryPage && queryFormData.value) {
      tableData.value = await queryPage(queryFormData.value)

      const query = omit(queryFormData.value, 'current', 'size') as LocationQuery
      const queryStr1 = Object.entries(query).filter(([value]) => value !== undefined).map(([key, value]) => `${key}=${value}`).join('&')
      const queryStr2 = Object.entries(route.query).map(([key, value]) => `${key}=${value}`).join('&')
      if (queryStr1 !== queryStr2) {
        await router.push({ query })
      }
    }
  }

  onMounted(() => {
    const params = useUrlSearchParams('hash')
    if (Object.keys(params).length > 0) {
      queryFormData.value = { ...params } as unknown as Q
      submitQuery()
    }
    else if (autoQuery) {
      submitQuery()
    }
  })

  async function submitQuery(current?: number) {
    if (queryFormData.value && current) {
      queryFormData.value.current = current
    }
    if (queryFormRef.value) {
      await queryFormRef.value.submitForm()
    }
    else {
      await doQuery()
    }
  }

  /**
   * 查询表单组件
   */
  const QueryForm = defineComponent(
    (props: DataQueryFormProp, { attrs, slots }) => {
      queryFormRef = useTemplateRef<ComponentExposed<typeof DataQueryForm>>('queryFormRef')

      return () => h(DataQueryForm<Q>, {
        'ref': 'queryFormRef',
        'fields': queryFormFields,
        'formData': queryFormData.value,
        'onUpdate:formData': value => queryFormData.value = value,
        'submit': async () => await doQuery(),
        ...props,
        ...attrs,
      }, slots)
    },
  )

  /**
   * 查询表格组件
   */
  const Table = defineComponent(
    (props: DataTableProps, { attrs, slots }) => {
      tableRef = useTemplateRef<ComponentExposed<typeof DataTable>>('tableRef')
      return () => h(DataTable<T>, {
        'ref': 'tableRef',
        'fields': dataTableFields,
        'queryData': queryFormData.value,
        'onUpdate:queryData': value => queryFormData.value = value,
        'tableData': tableData.value,
        'onUpdate:tableData': value => tableData.value = value,
        'onChange': submitQuery,
        ...props,
        ...attrs,
      }, slots)
    },
  )

  /**
   * 表格字段过滤按钮
   */
  const TableFieldFilterButton = defineComponent(
    (props: any, { attrs, slots }) => {
      return () => h(DateTableFieldFilterButton, {
        fields: dataTableFields,
        ...props,
        ...attrs,
      }, slots)
    },
  )

  function openRowEdit(index: number, submit: ((data: any) => Promise<any>), data?: any) {
    tableRef.value?.openRowEdit(index, submit, data)
  }

  function cancelRowEdit(index: number) {
    tableRef.value?.cancelRowEdit(index)
  }

  function submitRowEdit(index: number) {
    tableRef.value?.submitRowEdit(index)
  }

  function openRowEditAll(submit: ((data: any) => Promise<any>)) {
    tableRef.value?.openRowEditAll(submit)
  }

  function cancelRowEditAll() {
    tableRef.value?.cancelRowEditAll()
  }

  function submitRowEditAll() {
    tableRef.value?.submitRowEditAll()
  }

  return {
    queryFormData,
    tableData,
    QueryForm,
    Table,
    TableFieldFilterButton,
    submitQuery,
    openRowEdit,
    cancelRowEdit,
    submitRowEdit,
    openRowEditAll,
    cancelRowEditAll,
    submitRowEditAll,
  }
}
